/**
 * 1.future 是一个现在可能还没有准备好但将在未来某个时刻准备好的值
 * 2.Rust 提供了 Future trait 作为基础组件，这样不同的异步操作就可以在不同的数据结构上实现
 * 3.每一个实现了 Future 的类型会维护自己的进度状态信息和 “ready” 的定义
 * 4.async 关键字可以用于代码块和函数
 * 5.在一个 async 块或 async 函数中，可以使用 await 关键字来等待一个 future 准备就绪，这一过程称为 等待一个 future
 * 6.检查一个 future 并查看其值是否已经准备就绪的过程被称为 轮询（polling）
 *
 * 7.在大多数情况下，编写异步 Rust 代码时，我们使用 async 和 await 关键字。
 *    Rust 将其编译为等同于使用 Future trait 的代码，这非常类似于将 for 循环编译为等同于使用 Iterator trait 的代码
 * 
 * 测试代码
 * rust-script -d trpl 17.2_future.rs  https://www.cnblogs.com/lzfhope/p/18459068  https://www.cnblogs.com/lzfhope/p/18664452
 */
use trpl::{Either, Html};
use std::thread;

fn main() {
    let args: Vec<String> = std::env::args().collect();
    println!("{:?}", args);

    //注意async关键字，并不会导致开启一个新的线程，仅仅意味着可以在内部使用await关键字等待异步操作完成。
    trpl::run(async {
        //lazy future 这里不会执行
        let title_fut_1 = page_title(&args[1]);
        //lazy future 这里不会执行
        let title_fut_2 = page_title(&args[2]);

        //race中的代码使用future::select执行并发，并返回最先完成的future。
        //因为这里真正开始执行，所以才会在多次运行的时候，返回可能不同的结果
        //race方法返回的是一个Either类型，Either是一个枚举类型，有两个值，Left和Right。
        let (url, maybe_title) = match trpl::race(title_fut_1, title_fut_2).await {
            Either::Left(left) => left,
            Either::Right(right) => right,
        };

        println!("{url} returned first");
        match maybe_title {
            Some(title) => println!("Its page title is: '{title}'"),
            None => println!("Its title could not be parsed."),
        }
    })
}
/**
 * 带了async的函数会返回一个future，这个future的类型是impl Future<Output = ()>，
 * output是一个泛型参数，这里是()，表示这个future的返回值是一个元组，
 */
async fn page_title(url: &str) -> (&str, Option<String>) {
    //这个语句会证实函数page_title是运行在主线程中...,并不是多线程的.
    println!("{}",url);
    println!("线程{:?}正在执行", thread::current().id());
    let text = trpl::get(url).await.text().await;
    let title = Html::parse(&text)
        .select_first("title")
        .map(|title| title.inner_html());
    (url, title)
}
